import org.json.JSONObject;

//此工具类封装的报文,会包含封装报文的大小!!(但是需要自己调用MessageToChunk函数)
public class MessageEncapsulationUtils {
    //概述:判断报文的类型
    //参数:Message报文字节数组
    //返回值:一个int,即报文类型
    static int JudgeMessageType(byte[] Message) {
        //报文的第一个byte元素说明了报文的类别
        //type = 0为心跳包
        int type = Message[0] + 0;
        return type;
    }

    //概述:给报文Message加上包含了"报文大小"信息的头部
    //参数:Message报文字节数组
    //返回值:数据块chunk,一个byte[]数组
    static byte[] MessageToChunk(byte[] Message) {
        byte[] chunk = new byte[Message.length + 4];
        byte[] size_byte_arr = NetChunkUtil.intToByteArray(Message.length);
        System.arraycopy(size_byte_arr, 0, chunk, 0, 4);
        System.arraycopy(Message, 0, chunk, 4, Message.length);
        return chunk;
    }

    //概述:心跳报文打包
    //功能:把心跳包序号装进包里
    //参数:SerialNumber心跳报文序号
    //返回值:心跳报文字节数组
    static byte[] HeartBeatMessage_pack(int SerialNumber) {
        byte[] msg = new byte[8];
        msg[0] = 0;//报文的第一个byte元素说明了报文的类别,type = 0为心跳包
        byte[] snum_byte_arr = NetChunkUtil.intToByteArray(SerialNumber);
        System.arraycopy(snum_byte_arr, 0, msg, 1, 4);
        return msg;
    }

    //概述:心跳报文拆包
    //参数:HeartBeatMessage心跳报文字节数组
    //返回值:此心跳包的序号
    static int HeartBeatMessage_unpack(byte[] HeartBeatMessage) {
        byte[] snum_byte_arr = new byte[4];
        System.arraycopy(HeartBeatMessage, 1, snum_byte_arr, 0, 4);
        return NetChunkUtil.byteArrayToInt(snum_byte_arr);
    }

    //概述:"自己的文件持有表json"打包
    //参数:"自己的文件持有表"(由FileHoldingListSelf对象)
    //返回值:byte数组
    //功能:先把FileHoldingListSelf转换为Json,再把Json转换为字符串,再把字符串转换为byte数组
    //然后封上包头,此包包头type = 1
    //这里调用FHLS.toJSON(),会给FHLS对象加锁,线程安全
    static byte[] FHL_S_pack(FileHoldingListSelf FHLS) {
        byte[] FCL_S_str_byte = FHLS.toJSON().toString().getBytes();
        byte[] message = new byte[FCL_S_str_byte.length + 1];
        message[0] = 1;//封上包头
        System.arraycopy(FCL_S_str_byte, 0, message, 1, FCL_S_str_byte.length);
        return message;
    }

    //概述:"自己的文件持有表json"打包
    //参数:byte[] message
    //返回值:FileHoldingListSelf
    //然后封上包头,此包包头type = 1
    //此处调用FHLS.toFileHoldingListSelf,会给对象加锁,线程安全
    static FileHoldingListSelf FHL_S_unpack(byte[] message) {
        byte[] FCL_S_str_byte = new byte[message.length - 1];
        System.arraycopy(message, 1, FCL_S_str_byte, 0, message.length - 1);
        String str = new String(FCL_S_str_byte);
        FileHoldingListSelf FHLS = new FileHoldingListSelf();
        FHLS.toFileHoldingListSelf(new JSONObject(str));
        return FHLS;
    }

    //概述:"自己的文件持有表json"打包
    //参数:byte[] message
    //返回值:FileHoldingListSelf
    //然后封上包头,此包包头type = 1
    //此处调用FHLS.toFileHoldingListSelf,线程安全
    static FileHoldingListSelf FHL_S_unpack_init(byte[] message) {
        byte[] FCL_S_str_byte = new byte[message.length - 1];
        System.arraycopy(message, 1, FCL_S_str_byte, 0, message.length - 1);
        String str = new String(FCL_S_str_byte);
        FileHoldingListSelf FHLS = new FileHoldingListSelf();
        FHLS.toFileHoldingListSelf_inital(new JSONObject(str));
        return FHLS;
    }

    //概述:"自己的文件持有表json"打包
    //参数:"自己的文件持有表"(由FileHoldingListSelf对象)
    //返回值:String
    //功能:先把FileHoldingListSelf转换为Json,再把Json转换为字符串,再把字符串转换为byte数组
    //然后封上包头,此包包头type = 1
    static String FHL_S_unpack_toString(byte[] message) {
        byte[] FCL_S_str_byte = new byte[message.length - 1];
        System.arraycopy(message, 1, FCL_S_str_byte, 0, message.length - 1);
        String str = new String(FCL_S_str_byte);
        return str;
    }

    //概述:"文件片索要报文"(打包)
    //给谁用: 索要报文打包函数 是 "索要线程AskForThread"使用的,用于把他要发的[索要报文]打包
    //参数:whole_file_md5整个文件md5值,serial_num文件片序号
    //返回值:byte数组
    static byte[] AskForMessage_pack(String whole_file_md5, int serial_num) {
        //返回值byte数组为的长度为 16+4 即128bit的md5值和32位的序号值
        byte[] md5 = Md5CaculateUtil.MD5ArrFromStringToHex(whole_file_md5);
        byte[] num_byte = NetChunkUtil.intToByteArray(serial_num);
        byte[] message = new byte[20];
        System.arraycopy(md5, 0, message, 0, 16);
        System.arraycopy(num_byte, 0, message, 16, 4);
        return message;
    }

    //概述:"文件片索要报文"(拆包)
    //给谁用: 索要报文拆包函数 是 "资源持有线程ResourceHoldingThread"使用的,用于解析发过来的[索要报文]
    //参数:byte数组
    //返回值:whole_file_md5整个文件md5值,serial_num文件片序号(这几个东西打包在"资源持有线程消息队列"里面)
    //注意!!!返回值RRQI不包括"ip"这个字段!!!仍需要手动添加!!
    static ResourceHolding_ResponseQueue_info AskForMessage_pack(byte[] message) {
        ResourceHolding_ResponseQueue_info RRQI = new ResourceHolding_ResponseQueue_info();
        //把报文分段读出来
        byte[] md5 = new byte[16];
        System.arraycopy(message, 0, md5, 0, 16);
        byte[] num_byte = new byte[4];
        System.arraycopy(message, 16, num_byte, 0, 4);
        int serial_num = NetChunkUtil.byteArrayToInt(num_byte);
        String whole_file_md5 = Md5CaculateUtil.MD5ArrFromHexToString(md5);
        RRQI.file_md5 = whole_file_md5;
        RRQI.serial_num = serial_num;
        return RRQI;
    }
}
